/**
 * 
 */
package com.desksoft.ecommerce.util.expr;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.desksoft.utility.json.JSONUtil;
import com.desksoft.utility.string.StringUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/***************************************
 * <pre>
 * 版权所有：杭州迪科软件 保留所有权利
 * 创建日期: Sep 14, 2011 4:23:35 PM
 * 创建作者：yejw
 * 文件名称：Expression.java
 * 版本：
 * 功能：
 * 最后修改时间：Sep 14, 2011 4:23:35 PM
 * 修改记录：
 * </pre>
 *****************************************/

public class Expression implements Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1730344171433243018L;
	
	/**
	 * 属性集合
	 */
	private Map<String, Map<String, Object>> props = Maps.newLinkedHashMap();
	
	/**
	 * 字符编码
	 */
	private String encoding = null;

	public Expression() {}
	
	public Expression(String strProps) {
		this.analysisJSONStr(strProps);
	}
	
	public Expression(String strProps, String encode) {
		this.encoding = encode;
		this.analysisJSONStr(strProps);
	}
	
	/**
	 * 设置JSON字符串形式的属性集合
	 * 
	 * @param jsonStr
	 * @param encoding
	 */
	@SuppressWarnings("unchecked")
	public void analysisJSONStr(String jsonStr) {
		checkNotNull(jsonStr);
		
		Object o = null;
		Object paramVal = null;
		Map<String, Object> paramsMap = null;
		
		if (StringUtils.isNotBlank(this.encoding)) {
			try {
				jsonStr = URLDecoder.decode(jsonStr, encoding);
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
		
		Map<String, Object> condsMap = JSONUtil.readMap(jsonStr);
		if (condsMap == null) {
			return;
		}
		
		//条件表达式
		conditions: for (String cond : condsMap.keySet()) {
			o = condsMap.get(cond);
			if (o == null) {
				continue conditions;
			}
			
			paramsMap = (Map<String, Object>) o;
			
			//无参数
			if (paramsMap.isEmpty()) {
				this.put(cond);
			}
			
			//带参数
			params: for (String paramName : paramsMap.keySet()) {
				paramVal = paramsMap.get(paramName);
				if (paramVal == null) {
					continue params;
				}
				
				this.put(cond, paramName, paramVal);
			}
		}
	}
	
	/**
	 * 添加条件表达式
	 * 
	 * @param condition		条件ID, 如: A_1
	 */
	public void put(String condition) {
		checkNotNull(condition);
		
		this.props.put(condition, null);
	}
	
	/**
	 * 添加条件表达式
	 * 
	 * @param condition		条件ID, 如: A_1
	 * @param propName		属性名称
	 * @param propVal		属性值
	 */
	public void put(String condition, String propName, Object propVal) {
		checkNotNull(condition);
		
		boolean isNew = false;
		Map<String, Object> propMap = null;
		
		if (this.props.containsKey(condition)) {
			propMap = this.props.get(condition);
			
			if (propMap == null) {
				isNew = true;
				propMap = Maps.newLinkedHashMap();
			}
			
			propMap.put(propName, propVal);
			
			if (isNew) {
				this.props.put(condition, propMap);
			}
			
			return;
		}
		
		propMap = Maps.newLinkedHashMap();
		propMap.put(propName, propVal);
		
		this.props.put(condition, propMap);
	}

	/**
	 * 获取已完成组装的条件表达
	 *  
	 * @return
	 */
	public String get() {
		Map<String, Object> params = null;
		List<String> conds = Lists.newLinkedList(); 
		
		for (String condition : this.props.keySet()) {
			params = this.props.get(condition);
			
			conds.add(StringUtil.join(condition, params == null ? "" : ExprUtil.toJSON(params)));
		}
		
		return StringUtil.format("-", conds.toArray(new Object[]{}));
	}
	
	/**
	 * 是否已经包含指定条件
	 * 
	 * @param cond
	 * @return
	 */
	public boolean has(String cond) {
		return this.props.containsKey(cond);
	}
	
	/**
	 * 获取指定条件的全部参数
	 * 
	 * @param cond
	 * @return
	 */
	public Map<String, Object> getParam(String cond) {
		return this.props.get(cond);
	}
	
	/**
	 * 获取指定条件的参数
	 * 
	 * @param cond
	 * @param paramName
	 * @return
	 */
	public Object getParam(String cond, String paramName) {
		Map<String, Object> params = this.props.get(cond);
		
		if (params != null) {
			return params.get(paramName);
		}
		
		return null;
	}
	
	/**
	 * @return the encoding
	 */
	public String getEncoding() {
		return encoding;
	}

	/**
	 * @param encoding the encoding to set
	 */
	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}
	
}
